var request = require('supertest');
var should = require('should');
var testUtils = require("../../test/testUtils");
request = request(testUtils.url);

var APP_KEY = "";
var API_KEY_ADMIN = "";
var APP_ID = "";
var DEVICE_ID = "1234567890";
var COMMENT_ID = "";
var CRASHES = [];
var CRASH_URL = "";
var RE = /^-{0,1}\d*\.{0,1}\d+$/;

function verifyMetrics(ob, correct){
	ob.should.not.be.empty;
	if(ob["meta"]){
		for(var i in ob["meta"])
			ob["meta"][i].sort()
	}
	if(correct["meta"]){
		for(var i in correct["meta"])
			correct["meta"][i].sort()
	}
	ob.should.have.property("meta").eql(correct.meta);
	for(i in ob)
	{
        if(i != "meta"){
            ob.should.have.property(i).and.not.eql({});
            if(RE.test(i))
            {
                for(var c in correct){
                    if(c != "meta")
                        ob[i].should.have.property(c, correct[c]);
                }
                for(j in ob[i])
                {
                    if(RE.test(j))
                    {
                        for(var c in correct){
                            if(c != "meta")
                                ob[i][j].should.have.property(c, correct[c]);
                        }
                        for(k in ob[i][j])
                        {
                            if(RE.test(k))
                            {
                                for(var c in correct){
                                    if(c != "meta")
                                        ob[i][j][k].should.have.property(c, correct[c]);
                                }
                            }
                        }
                    }
                }
            }
        }
	}
};

describe('Testing Crashes', function(){
//{"users":{"total":0,"affected":0,"fatal":0,"nonfatal":0},"crashes":{"total":0,"unique":0,"resolved":0,"unresolved":0,"fatal":0,"nonfatal":0,"news":0,"renewed":0,"os":{},"highest_app":""},"loss":0,"groups":[],"data":{}}
    
	describe('Empty crashes', function(){
		it('should have no crashes', function(done){
			API_KEY_ADMIN = testUtils.get("API_KEY_ADMIN");
			APP_ID = testUtils.get("APP_ID");
			APP_KEY = testUtils.get("APP_KEY");
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":0,"affected":0,"fatal":0,"nonfatal":0});
                ob.should.have.property("crashes", {"total":0,"unique":0,"resolved":0,"unresolved":0,"fatal":0,"nonfatal":0,"news":0,"renewed":0,"os":{},"highest_app":""});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data", {});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Create user', function(){
		it('should success', function(done){
			request
			.get('/i?device_id='+DEVICE_ID+'1&app_key='+APP_KEY+"&begin_session=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Add crash', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "Android";
            crash._os_version = "4.0";
            crash._device = "Galaxy S3";
            crash._manufacture = "Samsung";
            crash._resolution = "480x800";
            crash._app_version = "1.1";
            crash._cpu = "armv7";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 2*1024;
			crash._ram_current = 1024;
			crash._disk_total = 10*1024;
			crash._disk_current = 2*1024;
			crash._bat_total = 100;
			crash._bat_current = 40;
			crash._orientation = "landscape";
            
			crash._root = true;
			crash._online = false;
			crash._signal = true;
			crash._muted = false;
			crash._background = true;
            
			crash._error = "java.lang.NullPointerException: com.domain.app.Exception<init>\nat com.domain.app.<init>(Activity.java:32)\nat com.domain.app.<init>(Activity.java:24)\nat com.domain.app.<init>(Activity.java:12)";
            crash._nonfatal = true;
            crash._run = 60;
            
            crash._custom = {
                "facebook" : "3.0",
                "googleplay" : "1.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'1&app_key='+APP_KEY+"&crash="+JSON.stringify(crash))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have 1 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":1,"affected":1,"fatal":0,"nonfatal":1});
                ob.should.have.property("crashes", {"total":1,"unique":1,"resolved":0,"unresolved":1,"fatal":0,"nonfatal":1,"news":1,"renewed":0,"os":{"Android":1},"highest_app":"1.1"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 1, crnf: 1, cru: 1});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should have 1 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 1);
                ob.should.have.property("iTotalDisplayRecords", 1);
                var crash = ob.aaData[0];
                crash.should.have.property("_id");
                crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                crash.should.have.property("is_new", true);
                crash.should.have.property("is_resolved", false);
                crash.should.have.property("lastTs");
                crash.should.have.property("latest_version", "1.1");
                crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                crash.should.have.property("nonfatal", true);
                crash.should.have.property("os", 'Android');
                crash.should.have.property("reports", 1);
                crash.should.have.property("users", 1);
                CRASHES[0] = crash._id;
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have provided details', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",true);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.1");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"4:0":1});
                ob.should.have.property("manufacture",{"Samsung":1});
                ob.should.have.property("device",{"Galaxy S3":1});
                ob.should.have.property("resolution",{"480x800":1});
                ob.should.have.property("app_version",{"1:1":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"landscape":1});
                ob.should.have.property("custom",{"facebook":{"3:0":1},"googleplay":{"1:0":1}});
                ob.should.have.property("root",{"yes":1});
                ob.should.have.property("online",{"no":1});
                ob.should.have.property("muted",{"no":1});
                ob.should.have.property("signal",{"yes":1});
                ob.should.have.property("background",{"yes":1});
                ob.should.have.property("ram",{"total":50,"count":1,"min":50,"max":50});
                ob.should.have.property("bat",{"total":40,"count":1,"min":40,"max":40});
                ob.should.have.property("disk",{"total":20,"count":1,"min":20,"max":20});
                ob.should.have.property("run",{"total":60,"count":1,"min":60,"max":60});
                ob.should.have.property("total",1);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(1);
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Android");
                report.should.have.property("os_version","4.0");
                report.should.have.property("manufacture","Samsung");
                report.should.have.property("device","Galaxy S3");
                report.should.have.property("resolution","480x800");
                report.should.have.property("app_version","1.1");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",1024);
                report.should.have.property("ram_total",2048);
                report.should.have.property("disk_current",2048);
                report.should.have.property("disk_total",10240);
                report.should.have.property("bat_current",40);
                report.should.have.property("bat_total",100);
                report.should.have.property("orientation","landscape");
                report.should.have.property("root",1);
                report.should.have.property("signal",1);
                report.should.have.property("background",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",true);
                report.should.have.property("run",60);
                report.should.have.property("custom",{"facebook":"3.0","googleplay":"1.0"});
                report.should.have.property("group",CRASHES[0]);
                report.should.have.property("uid","1");
                report.should.have.property("ts");
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Create user', function(){
		it('should success', function(done){
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&begin_session=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Add same crash for new user', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "Android";
            crash._os_version = "4.0";
            crash._device = "Galaxy S3";
            crash._manufacture = "Samsung";
            crash._resolution = "480x800";
            crash._app_version = "1.1";
            crash._cpu = "armv7";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 2*1024;
			crash._ram_current = 1024;
			crash._disk_total = 10*1024;
			crash._disk_current = 2*1024;
			crash._bat_total = 100;
			crash._bat_current = 40;
			crash._orientation = "landscape";
            
			crash._root = true;
			crash._online = false;
			crash._signal = true;
			crash._muted = false;
			crash._background = true;
            
			crash._error = "java.lang.NullPointerException: com.domain.app.Exception<init>\nat com.domain.app.<init>(Activity.java:32)\nat com.domain.app.<init>(Activity.java:24)\nat com.domain.app.<init>(Activity.java:12)";
            crash._nonfatal = true;
            crash._run = 60;
            
            crash._custom = {
                "facebook" : "3.0",
                "googleplay" : "1.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&crash="+JSON.stringify(crash))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have 1 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":2,"affected":2,"fatal":0,"nonfatal":2});
                ob.should.have.property("crashes", {"total":2,"unique":1,"resolved":0,"unresolved":1,"fatal":0,"nonfatal":2,"news":0,"renewed":0,"os":{"Android":2},"highest_app":"1.1"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 2, crnf: 2, cru: 1});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should have 1 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 1);
                ob.should.have.property("iTotalDisplayRecords", 1);
                ob.should.have.property("aaData").with.lengthOf(1);
                var crash = ob.aaData[0];
                crash.should.have.property("_id", CRASHES[0]);
                crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                crash.should.have.property("is_new", false);
                crash.should.have.property("is_resolved", false);
                crash.should.have.property("lastTs");
                crash.should.have.property("latest_version", "1.1");
                crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                crash.should.have.property("nonfatal", true);
                crash.should.have.property("os", 'Android');
                crash.should.have.property("reports", 2);
                crash.should.have.property("users", 2);
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have provided details', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.1");
                ob.should.have.property("reports",2);
                ob.should.have.property("users",2);
                ob.should.have.property("os_version",{"4:0":2});
                ob.should.have.property("manufacture",{"Samsung":2});
                ob.should.have.property("device",{"Galaxy S3":2});
                ob.should.have.property("resolution",{"480x800":2});
                ob.should.have.property("app_version",{"1:1":2});
                ob.should.have.property("cpu",{"armv7":2});
                ob.should.have.property("opengl",{"openGL ES 2:0":2});
                ob.should.have.property("orientation",{"landscape":2});
                ob.should.have.property("custom",{"facebook":{"3:0":2},"googleplay":{"1:0":2}});
                ob.should.have.property("root",{"yes":2});
                ob.should.have.property("online",{"no":2});
                ob.should.have.property("muted",{"no":2});
                ob.should.have.property("signal",{"yes":2});
                ob.should.have.property("background",{"yes":2});
                ob.should.have.property("ram",{"total":100,"count":2,"min":50,"max":50});
                ob.should.have.property("bat",{"total":80,"count":2,"min":40,"max":40});
                ob.should.have.property("disk",{"total":40,"count":2,"min":20,"max":20});
                ob.should.have.property("run",{"total":120,"count":2,"min":60,"max":60});
                ob.should.have.property("total",2);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(2);
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Android");
                report.should.have.property("os_version","4.0");
                report.should.have.property("manufacture","Samsung");
                report.should.have.property("device","Galaxy S3");
                report.should.have.property("resolution","480x800");
                report.should.have.property("app_version","1.1");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",1024);
                report.should.have.property("ram_total",2048);
                report.should.have.property("disk_current",2048);
                report.should.have.property("disk_total",10240);
                report.should.have.property("bat_current",40);
                report.should.have.property("bat_total",100);
                report.should.have.property("orientation","landscape");
                report.should.have.property("root",1);
                report.should.have.property("signal",1);
                report.should.have.property("background",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",true);
                report.should.have.property("run",60);
                report.should.have.property("custom",{"facebook":"3.0","googleplay":"1.0"});
                report.should.have.property("group",CRASHES[0]);
                report.should.have.property("uid","2");
                report.should.have.property("ts");
                
                var report2 = ob.data[1];
                report2.should.have.property("_id");
                report2.should.have.property("os","Android");
                report2.should.have.property("os_version","4.0");
                report2.should.have.property("manufacture","Samsung");
                report2.should.have.property("device","Galaxy S3");
                report2.should.have.property("resolution","480x800");
                report2.should.have.property("app_version","1.1");
                report2.should.have.property("cpu","armv7");
                report2.should.have.property("opengl","openGL ES 2.0");
                report2.should.have.property("ram_current",1024);
                report2.should.have.property("ram_total",2048);
                report2.should.have.property("disk_current",2048);
                report2.should.have.property("disk_total",10240);
                report2.should.have.property("bat_current",40);
                report2.should.have.property("bat_total",100);
                report2.should.have.property("orientation","landscape");
                report2.should.have.property("root",1);
                report2.should.have.property("signal",1);
                report2.should.have.property("background",1);
                report2.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report2.should.have.property("nonfatal",true);
                report2.should.have.property("run",60);
                report2.should.have.property("custom",{"facebook":"3.0","googleplay":"1.0"});
                report2.should.have.property("group",CRASHES[0]);
                report2.should.have.property("uid","1");
                report2.should.have.property("ts");
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Create another session for user', function(){
		it('should success', function(done){
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&begin_session=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Add same crash with different parameters for same user', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "Android";
            crash._os_version = "4.1";
            crash._device = "Galaxy S4";
            crash._manufacture = "Samsung";
            crash._resolution = "800x1900";
            crash._app_version = "1.2";
            crash._cpu = "armv7";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 4*1024;
			crash._ram_current = 3*1024;
			crash._disk_total = 20*1024;
			crash._disk_current = 5*1024;
			crash._bat_total = 100;
			crash._bat_current = 90;
			crash._orientation = "portrait";
            
			crash._root = false;
			crash._online = true;
			crash._signal = false;
			crash._muted = true;
			crash._background = false;
            
			crash._error = "java.lang.NullPointerException: com.domain.app.Exception<init>\nat com.domain.app.<init>(Activity.java:32)\nat com.domain.app.<init>(Activity.java:24)\nat com.domain.app.<init>(Activity.java:12)";
            crash._nonfatal = true;
            crash._run = 120;
            
            crash._custom = {
                "facebook" : "3.5",
                "googleplay" : "2.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&crash="+JSON.stringify(crash))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have 1 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":2,"affected":2,"fatal":0,"nonfatal":2});
                ob.should.have.property("crashes", {"total":3,"unique":1,"resolved":0,"unresolved":1,"fatal":0,"nonfatal":3,"news":0,"renewed":0,"os":{"Android":3},"highest_app":"1.2"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 3, crnf: 3, cru: 1});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should have 1 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 1);
                ob.should.have.property("iTotalDisplayRecords", 1);
                ob.should.have.property("aaData").with.lengthOf(1);
                var crash = ob.aaData[0];
                crash.should.have.property("_id", CRASHES[0]);
                crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                crash.should.have.property("is_new", false);
                crash.should.have.property("is_resolved", false);
                crash.should.have.property("lastTs");
                crash.should.have.property("latest_version", "1.2");
                crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                crash.should.have.property("nonfatal", true);
                crash.should.have.property("os", 'Android');
                crash.should.have.property("reports", 3);
                crash.should.have.property("users", 2);
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have provided details', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",3);
                ob.should.have.property("users",2);
                ob.should.have.property("os_version",{"4:0":2, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":3});
                ob.should.have.property("device",{"Galaxy S3":2, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":2, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1});
                ob.should.have.property("cpu",{"armv7":3});
                ob.should.have.property("opengl",{"openGL ES 2:0":3});
                ob.should.have.property("orientation",{"landscape":2, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":2, "3:5":1},"googleplay":{"1:0":2, "2:0":1}});
                ob.should.have.property("root",{"yes":2, "no":1});
                ob.should.have.property("online",{"no":2, "yes":1});
                ob.should.have.property("muted",{"no":2, "yes":1});
                ob.should.have.property("signal",{"yes":2, "no":1});
                ob.should.have.property("background",{"yes":2, "no":1});
                ob.should.have.property("ram",{"total":175,"count":3,"min":50,"max":75});
                ob.should.have.property("bat",{"total":170,"count":3,"min":40,"max":90});
                ob.should.have.property("disk",{"total":65,"count":3,"min":20,"max":25});
                ob.should.have.property("run",{"total":240,"count":3,"min":60,"max":120});
                ob.should.have.property("session",{"total":1,"count":1,"min":1,"max":1});
                ob.should.have.property("total",2);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(3);
                
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Android");
                report.should.have.property("os_version","4.1");
                report.should.have.property("manufacture","Samsung");
                report.should.have.property("device","Galaxy S4");
                report.should.have.property("resolution","800x1900");
                report.should.have.property("app_version","1.2");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",3*1024);
                report.should.have.property("ram_total",4*1024);
                report.should.have.property("disk_current",5*1024);
                report.should.have.property("disk_total",20*1024);
                report.should.have.property("bat_current",90);
                report.should.have.property("bat_total",100);
                report.should.have.property("session",1);
                report.should.have.property("orientation","portrait");
                report.should.have.property("online",1);
                report.should.have.property("muted",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",true);
                report.should.have.property("run",120);
                report.should.have.property("custom",{"facebook":"3.5","googleplay":"2.0"});
                report.should.have.property("group",CRASHES[0]);
                report.should.have.property("uid","2");
                report.should.have.property("ts");
                
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Add same crash with different fatality', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "Android";
            crash._os_version = "4.1";
            crash._device = "Galaxy S4";
            crash._manufacture = "Samsung";
            crash._resolution = "800x1900";
            crash._app_version = "1.2";
            crash._cpu = "armv7";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 4*1024;
			crash._ram_current = 3*1024;
			crash._disk_total = 20*1024;
			crash._disk_current = 5*1024;
			crash._bat_total = 100;
			crash._bat_current = 90;
			crash._orientation = "portrait";
            
			crash._root = false;
			crash._online = true;
			crash._signal = false;
			crash._muted = true;
			crash._background = false;
            
			crash._error = "java.lang.NullPointerException: com.domain.app.Exception<init>\nat com.domain.app.<init>(Activity.java:32)\nat com.domain.app.<init>(Activity.java:24)\nat com.domain.app.<init>(Activity.java:12)";
            crash._nonfatal = false;
            crash._run = 120;
            
            crash._custom = {
                "facebook" : "3.5",
                "googleplay" : "2.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&crash="+JSON.stringify(crash))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have 2 crashes', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":2,"affected":2,"fatal":1,"nonfatal":1});
                ob.should.have.property("crashes", {"total":4,"unique":2,"resolved":0,"unresolved":2,"fatal":1,"nonfatal":3,"news":1,"renewed":0,"os":{"Android":4},"highest_app":"1.2"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 4, crnf: 3, crf: 1, cru: 2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should have 2 crashes', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 2);
                ob.should.have.property("iTotalDisplayRecords", 2);
                ob.should.have.property("aaData").with.lengthOf(2);
                
                for(var i = 0; i < ob.aaData.length; i++){
                    var crash = ob.aaData[i];
                    if(crash._id == CRASHES[0]){
                        crash.should.have.property("_id", CRASHES[0]);
                        crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.2");
                        crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                        crash.should.have.property("nonfatal", true);
                        crash.should.have.property("os", 'Android');
                        crash.should.have.property("reports", 3);
                        crash.should.have.property("users", 2);
                    }
                    else{
                        crash.should.have.property("_id");
                        crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                        crash.should.have.property("is_new", true);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.2");
                        crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'Android');
                        crash.should.have.property("reports", 1);
                        crash.should.have.property("users", 1);
                        CRASHES[1] = crash._id;
                    }
                }
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have provided details', function(done){
			request
			.get('/o?group='+CRASHES[1]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[1]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",true);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"4:1":1});
                ob.should.have.property("manufacture",{"Samsung":1});
                ob.should.have.property("device",{"Galaxy S4":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1},"googleplay":{"2:0":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",2);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(1);
                
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Android");
                report.should.have.property("os_version","4.1");
                report.should.have.property("manufacture","Samsung");
                report.should.have.property("device","Galaxy S4");
                report.should.have.property("resolution","800x1900");
                report.should.have.property("app_version","1.2");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",3*1024);
                report.should.have.property("ram_total",4*1024);
                report.should.have.property("disk_current",5*1024);
                report.should.have.property("disk_total",20*1024);
                report.should.have.property("bat_current",90);
                report.should.have.property("bat_total",100);
                report.should.have.property("orientation","portrait");
                report.should.have.property("online",1);
                report.should.have.property("muted",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",false);
                report.should.have.property("run",120);
                report.should.have.property("custom",{"facebook":"3.5","googleplay":"2.0"});
                report.should.have.property("group",CRASHES[1]);
                report.should.have.property("uid","2");
                report.should.have.property("ts");
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Add same crash with different os with new user', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "Windows Phone";
            crash._os_version = "8.1";
            crash._device = "Lumia 560";
            crash._manufacture = "Nokia";
            crash._resolution = "800x1900";
            crash._app_version = "1.2";
            crash._cpu = "armv7";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 4*1024;
			crash._ram_current = 3*1024;
			crash._disk_total = 20*1024;
			crash._disk_current = 5*1024;
			crash._bat_total = 100;
			crash._bat_current = 90;
			crash._orientation = "portrait";
            
			crash._root = false;
			crash._online = true;
			crash._signal = false;
			crash._muted = true;
			crash._background = false;
            
			crash._error = "java.lang.NullPointerException: com.domain.app.Exception<init>\nat com.domain.app.<init>(Activity.java:32)\nat com.domain.app.<init>(Activity.java:24)\nat com.domain.app.<init>(Activity.java:12)";
            crash._nonfatal = false;
            crash._run = 120;
            
            crash._custom = {
                "facebook" : "3.5"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'3&app_key='+APP_KEY+"&begin_session=1&crash="+JSON.stringify(crash))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have 3 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":5,"unique":3,"resolved":0,"unresolved":3,"fatal":2,"nonfatal":3,"news":1,"renewed":0,"os":{"Android":4, "Windows Phone":1},"highest_app":"1.2"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 5, crnf: 3, crf: 2, cru: 3});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should have 3 crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 3);
                ob.should.have.property("iTotalDisplayRecords", 3);
                ob.should.have.property("aaData").with.lengthOf(3);
                
                for(var i = 0; i < ob.aaData.length; i++){
                    var crash = ob.aaData[i];
                    if(crash._id != CRASHES[0] && crash._id != CRASHES[1]){
                        crash.should.have.property("_id");
                        crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                        crash.should.have.property("is_new", true);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.2");
                        crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'Windows Phone');
                        crash.should.have.property("reports", 1);
                        crash.should.have.property("users", 1);
                        CRASHES[2] = crash._id;
                    }
                }
                setTimeout(done, 1000);
            });
		});
	});
    
    describe('Check crash details', function(){
		it('should have provided details', function(done){
			request
			.get('/o?group='+CRASHES[2]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[2]);
                ob.should.have.property("os","Windows Phone");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",true);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.have.property("manufacture",{"Nokia":1});
                ob.should.have.property("device",{"Lumia 560":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(1);
                
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Windows Phone");
                report.should.have.property("os_version","8.1");
                report.should.have.property("manufacture","Nokia");
                report.should.have.property("device","Lumia 560");
                report.should.have.property("resolution","800x1900");
                report.should.have.property("app_version","1.2");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",3*1024);
                report.should.have.property("ram_total",4*1024);
                report.should.have.property("disk_current",5*1024);
                report.should.have.property("disk_total",20*1024);
                report.should.have.property("bat_current",90);
                report.should.have.property("bat_total",100);
                report.should.have.property("orientation","portrait");
                report.should.have.property("online",1);
                report.should.have.property("muted",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",false);
                report.should.have.property("run",120);
                report.should.have.property("custom",{"facebook":"3.5"});
                report.should.have.property("group",CRASHES[2]);
                report.should.have.property("uid","3");
                report.should.have.property("ts");
                
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Hide crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2]
            };
			request
			.get('/i/crashes/hide?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should be hidden', function(done){
			request
			.get('/o?group='+CRASHES[2]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[2]);
                ob.should.have.property("os","Windows Phone");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_hidden",true);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.have.property("manufacture",{"Nokia":1});
                ob.should.have.property("device",{"Lumia 560":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(1);
                
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Windows Phone");
                report.should.have.property("os_version","8.1");
                report.should.have.property("manufacture","Nokia");
                report.should.have.property("device","Lumia 560");
                report.should.have.property("resolution","800x1900");
                report.should.have.property("app_version","1.2");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",3*1024);
                report.should.have.property("ram_total",4*1024);
                report.should.have.property("disk_current",5*1024);
                report.should.have.property("disk_total",20*1024);
                report.should.have.property("bat_current",90);
                report.should.have.property("bat_total",100);
                report.should.have.property("orientation","portrait");
                report.should.have.property("online",1);
                report.should.have.property("muted",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",false);
                report.should.have.property("run",120);
                report.should.have.property("custom",{"facebook":"3.5"});
                report.should.have.property("group",CRASHES[2]);
                report.should.have.property("uid","3");
                report.should.have.property("ts");
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Show crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2]
            };
			request
			.get('/i/crashes/show?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should be visible', function(done){
			request
			.get('/o?group='+CRASHES[2]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[2]);
                ob.should.have.property("os","Windows Phone");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_hidden",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.have.property("manufacture",{"Nokia":1});
                ob.should.have.property("device",{"Lumia 560":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(1);
                CRASH_URL = ob.url;
                
                var report = ob.data[0];
                report.should.have.property("_id");
                report.should.have.property("os","Windows Phone");
                report.should.have.property("os_version","8.1");
                report.should.have.property("manufacture","Nokia");
                report.should.have.property("device","Lumia 560");
                report.should.have.property("resolution","800x1900");
                report.should.have.property("app_version","1.2");
                report.should.have.property("cpu","armv7");
                report.should.have.property("opengl","openGL ES 2.0");
                report.should.have.property("ram_current",3*1024);
                report.should.have.property("ram_total",4*1024);
                report.should.have.property("disk_current",5*1024);
                report.should.have.property("disk_total",20*1024);
                report.should.have.property("bat_current",90);
                report.should.have.property("bat_total",100);
                report.should.have.property("orientation","portrait");
                report.should.have.property("online",1);
                report.should.have.property("muted",1);
                report.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                report.should.have.property("nonfatal",false);
                report.should.have.property("run",120);
                report.should.have.property("custom",{"facebook":"3.5"});
                report.should.have.property("group",CRASHES[2]);
                report.should.have.property("uid","3");
                report.should.have.property("ts");
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check public crash', function(){
		it('should not found', function(done){
			request
			.get('/crash/'+CRASH_URL)
			.expect(404, done);
		});
	});
    
    describe('Make crash public', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2]
            };
			request
			.get('/i/crashes/share?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check public crash', function(){
		it('should be found', function(done){
			request
			.get('/crash/'+CRASH_URL)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
                var parts = res.text.split("var crash_data = ");
                parts.should.have.lengthOf(2);
                var data = parts[1].split(";\nwindow.CrashgroupView")[0];
				var ob = JSON.parse(data);
				ob.should.not.have.property('loss');
				ob.should.not.have.property('users');
				ob.should.not.have.property('data');
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Publish specfic properties', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2],
                data:{
                    reports: 1,
                    loss: 1,
                    users:1
                }
            };
			request
			.get('/i/crashes/modify_share?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check published properties', function(){
		it('should be found', function(done){
			request
			.get('/crash/'+CRASH_URL)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
                var parts = res.text.split("var crash_data = ");
                parts.should.have.lengthOf(2);
                var data = parts[1].split(";\nwindow.CrashgroupView")[0];
				var ob = JSON.parse(data);
				ob.should.have.property('share', {"reports":1,"loss":1,"users":1});
				ob.should.have.property('users');
				ob.should.have.property('data');
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Unmake crash public', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2]
            };
			request
			.get('/i/crashes/unshare?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check public crash', function(){
		it('should not found', function(done){
			request
			.get('/crash/'+CRASH_URL)
			.expect(404, done);
		});
	});
    
    describe('Add comment', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2],
                text: "Test comment",
                app_id:APP_ID,
            };
			request
			.get('/i/crashes/add_comment?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have comment', function(done){
			request
			.get('/o?group='+CRASHES[2]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[2]);
                ob.should.have.property("os","Windows Phone");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_hidden",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.have.property("manufacture",{"Nokia":1});
                ob.should.have.property("device",{"Lumia 560":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("comments").with.lengthOf(1);
                var comment = ob.comments[0];
                comment.should.have.property("text", "Test comment");
                comment.should.have.property("time");
                comment.should.have.property("author");
                comment.should.have.property("author_id");
                comment.should.have.property("_id");
                COMMENT_ID = comment._id;
                ob.should.have.property("data").with.lengthOf(1);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Edit comment', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2],
                text: "Test comment edited",
                app_id:APP_ID,
                comment_id: COMMENT_ID
            };
			request
			.get('/i/crashes/edit_comment?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have edited comment', function(done){
			request
			.get('/o?group='+CRASHES[2]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[2]);
                ob.should.have.property("os","Windows Phone");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_hidden",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.have.property("manufacture",{"Nokia":1});
                ob.should.have.property("device",{"Lumia 560":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("comments").with.lengthOf(1);
                var comment = ob.comments[0];
                comment.should.have.property("text", "Test comment edited");
                comment.should.have.property("time");
                comment.should.have.property("edit_time");
                comment.should.have.property("author");
                comment.should.have.property("author_id");
                comment.should.have.property("_id");
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Delete comment', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2],
                app_id:APP_ID,
                comment_id: COMMENT_ID
            };
			request
			.get('/i/crashes/delete_comment?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have no comments', function(done){
			request
			.get('/o?group='+CRASHES[2]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[2]);
                ob.should.have.property("os","Windows Phone");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_hidden",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.have.property("manufacture",{"Nokia":1});
                ob.should.have.property("device",{"Lumia 560":1});
                ob.should.have.property("resolution",{"800x1900":1});
                ob.should.have.property("app_version",{"1:2":1});
                ob.should.have.property("cpu",{"armv7":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:5":1}});
                ob.should.have.property("root",{"no":1});
                ob.should.have.property("online",{"yes":1});
                ob.should.have.property("muted",{"yes":1});
                ob.should.have.property("signal",{"no":1});
                ob.should.have.property("background",{"no":1});
                ob.should.have.property("ram",{"total":75,"count":1,"min":75,"max":75});
                ob.should.have.property("bat",{"total":90,"count":1,"min":90,"max":90});
                ob.should.have.property("disk",{"total":25,"count":1,"min":25,"max":25});
                ob.should.have.property("run",{"total":120,"count":1,"min":120,"max":120});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("comments").with.lengthOf(0);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Resolve crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[0]
            };
			request
			.get('/i/crashes/resolve?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property(CRASHES[0],'1.2');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should be resolved', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":5,"unique":3,"resolved":1,"unresolved":2,"fatal":2,"nonfatal":3,"news":0,"renewed":0,"os":{"Android":4, "Windows Phone":1},"highest_app":"1.2"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 5, crnf: 3, crf: 2, cru: 3});
				setTimeout(done, 1000);
			});
		});
	});
       
    describe('Check crash details', function(){
		it('should be resolved', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",true);
                ob.should.have.property("resolved_version", "1.2");
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",3);
                ob.should.have.property("users",2);
                ob.should.have.property("os_version",{"4:0":2, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":3});
                ob.should.have.property("device",{"Galaxy S3":2, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":2, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1});
                ob.should.have.property("cpu",{"armv7":3});
                ob.should.have.property("opengl",{"openGL ES 2:0":3});
                ob.should.have.property("orientation",{"landscape":2, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":2, "3:5":1},"googleplay":{"1:0":2, "2:0":1}});
                ob.should.have.property("root",{"yes":2, "no":1});
                ob.should.have.property("online",{"no":2, "yes":1});
                ob.should.have.property("muted",{"no":2, "yes":1});
                ob.should.have.property("signal",{"yes":2, "no":1});
                ob.should.have.property("background",{"yes":2, "no":1});
                ob.should.have.property("ram",{"total":175,"count":3,"min":50,"max":75});
                ob.should.have.property("bat",{"total":170,"count":3,"min":40,"max":90});
                ob.should.have.property("disk",{"total":65,"count":3,"min":20,"max":25});
                ob.should.have.property("run",{"total":240,"count":3,"min":60,"max":120});
                ob.should.have.property("session",{"total":1,"count":1,"min":1,"max":1});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(3);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Upgrade user with multiple crashes to resolved version', function(){
		it('should success', function(done){
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&begin_session=1&metrics="+JSON.stringify({"_app_version": "1.3"}))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should no user change', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":5,"unique":3,"resolved":1,"unresolved":2,"fatal":2,"nonfatal":3,"news":0,"renewed":0,"os":{"Android":4, "Windows Phone":1},"highest_app":"1.2"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 5, crnf: 3, crf: 2, cru: 3, crru:1});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have 1 user less', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",true);
                ob.should.have.property("resolved_version", "1.2");
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",3);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"4:0":2, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":3});
                ob.should.have.property("device",{"Galaxy S3":2, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":2, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1});
                ob.should.have.property("cpu",{"armv7":3});
                ob.should.have.property("opengl",{"openGL ES 2:0":3});
                ob.should.have.property("orientation",{"landscape":2, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":2, "3:5":1},"googleplay":{"1:0":2, "2:0":1}});
                ob.should.have.property("root",{"yes":2, "no":1});
                ob.should.have.property("online",{"no":2, "yes":1});
                ob.should.have.property("muted",{"no":2, "yes":1});
                ob.should.have.property("signal",{"yes":2, "no":1});
                ob.should.have.property("background",{"yes":2, "no":1});
                ob.should.have.property("ram",{"total":175,"count":3,"min":50,"max":75});
                ob.should.have.property("bat",{"total":170,"count":3,"min":40,"max":90});
                ob.should.have.property("disk",{"total":65,"count":3,"min":20,"max":25});
                ob.should.have.property("run",{"total":240,"count":3,"min":60,"max":120});
                ob.should.have.property("session",{"total":1,"count":1,"min":1,"max":1});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(3);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Upgrade user with single crash to resolved version', function(){
		it('should success', function(done){
			request
			.get('/i?device_id='+DEVICE_ID+'1&app_key='+APP_KEY+"&begin_session=1&metrics="+JSON.stringify({"_app_version": "1.3"}))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 5000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have 1 user less', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":2,"fatal":2,"nonfatal":0});
                ob.should.have.property("crashes", {"total":5,"unique":3,"resolved":1,"unresolved":2,"fatal":2,"nonfatal":3,"news":0,"renewed":0,"os":{"Android":4, "Windows Phone":1},"highest_app":"1.2"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 5, crnf: 3, crf: 2, cru: 3, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should have no users affected', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",true);
                ob.should.have.property("resolved_version", "1.2");
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.2");
                ob.should.have.property("reports",3);
                ob.should.have.property("users",0);
                ob.should.have.property("os_version",{"4:0":2, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":3});
                ob.should.have.property("device",{"Galaxy S3":2, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":2, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1});
                ob.should.have.property("cpu",{"armv7":3});
                ob.should.have.property("opengl",{"openGL ES 2:0":3});
                ob.should.have.property("orientation",{"landscape":2, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":2, "3:5":1},"googleplay":{"1:0":2, "2:0":1}});
                ob.should.have.property("root",{"yes":2, "no":1});
                ob.should.have.property("online",{"no":2, "yes":1});
                ob.should.have.property("muted",{"no":2, "yes":1});
                ob.should.have.property("signal",{"yes":2, "no":1});
                ob.should.have.property("background",{"yes":2, "no":1});
                ob.should.have.property("ram",{"total":175,"count":3,"min":50,"max":75});
                ob.should.have.property("bat",{"total":170,"count":3,"min":40,"max":90});
                ob.should.have.property("disk",{"total":65,"count":3,"min":20,"max":25});
                ob.should.have.property("run",{"total":240,"count":3,"min":60,"max":120});
                ob.should.have.property("session",{"total":1,"count":1,"min":1,"max":1});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(3);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Create another user session', function(){
		it('should success', function(done){
			request
			.get('/i?device_id='+DEVICE_ID+'1&app_key='+APP_KEY+"&begin_session=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 5000);
			});
		});
	});
    
    describe('Resolved user has crash again', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "Android";
            crash._os_version = "4.0";
            crash._device = "Galaxy S3";
            crash._manufacture = "Samsung";
            crash._resolution = "480x800";
            crash._app_version = "1.3";
            crash._cpu = "armv7";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 2*1024;
			crash._ram_current = 1024;
			crash._disk_total = 10*1024;
			crash._disk_current = 2*1024;
			crash._bat_total = 100;
			crash._bat_current = 40;
			crash._orientation = "landscape";
            
			crash._root = true;
			crash._online = false;
			crash._signal = true;
			crash._muted = false;
			crash._background = true;
            
			crash._error = "java.lang.NullPointerException: com.domain.app.Exception<init>\nat com.domain.app.<init>(Activity.java:32)\nat com.domain.app.<init>(Activity.java:24)\nat com.domain.app.<init>(Activity.java:12)";
            crash._nonfatal = true;
            crash._run = 60;
            
            crash._custom = {
                "facebook" : "3.0",
                "googleplay" : "1.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'1&app_key='+APP_KEY+"&crash="+JSON.stringify(crash))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 5000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should be reoccurred', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":6,"unique":3,"resolved":0,"unresolved":3,"fatal":2,"nonfatal":4,"news":0,"renewed":1,"os":{"Android":5, "Windows Phone":1},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 6, crnf: 4, crf: 2, cru: 3, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should be resolved', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_renewed",true);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.3");
                ob.should.have.property("reports",4);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"4:0":3, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":4});
                ob.should.have.property("device",{"Galaxy S3":3, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":3, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1, "1:3":1});
                ob.should.have.property("cpu",{"armv7":4});
                ob.should.have.property("opengl",{"openGL ES 2:0":4});
                ob.should.have.property("orientation",{"landscape":3, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":3, "3:5":1},"googleplay":{"1:0":3, "2:0":1}});
                ob.should.have.property("root",{"yes":3, "no":1});
                ob.should.have.property("online",{"no":3, "yes":1});
                ob.should.have.property("muted",{"no":3, "yes":1});
                ob.should.have.property("signal",{"yes":3, "no":1});
                ob.should.have.property("background",{"yes":3, "no":1});
                ob.should.have.property("ram",{"total":225,"count":4,"min":50,"max":75});
                ob.should.have.property("bat",{"total":210,"count":4,"min":40,"max":90});
                ob.should.have.property("disk",{"total":85,"count":4,"min":20,"max":25});
                ob.should.have.property("run",{"total":300,"count":4,"min":60,"max":120});
                ob.should.have.property("session",{"total":3,"count":2,"min":1,"max":2});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(4);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Resolve crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[0]
            };
			request
			.get('/i/crashes/resolve?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property(CRASHES[0],'1.3');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should be reoccurred', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":6,"unique":3,"resolved":1,"unresolved":2,"fatal":2,"nonfatal":4,"news":0,"renewed":0,"os":{"Android":5, "Windows Phone":1},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 6, crnf: 4, crf: 2, cru: 3, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should be resolved', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",true);
                ob.should.have.property("is_renewed",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.3");
                ob.should.have.property("reports",4);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"4:0":3, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":4});
                ob.should.have.property("device",{"Galaxy S3":3, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":3, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1, "1:3":1});
                ob.should.have.property("cpu",{"armv7":4});
                ob.should.have.property("opengl",{"openGL ES 2:0":4});
                ob.should.have.property("orientation",{"landscape":3, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":3, "3:5":1},"googleplay":{"1:0":3, "2:0":1}});
                ob.should.have.property("root",{"yes":3, "no":1});
                ob.should.have.property("online",{"no":3, "yes":1});
                ob.should.have.property("muted",{"no":3, "yes":1});
                ob.should.have.property("signal",{"yes":3, "no":1});
                ob.should.have.property("background",{"yes":3, "no":1});
                ob.should.have.property("ram",{"total":225,"count":4,"min":50,"max":75});
                ob.should.have.property("bat",{"total":210,"count":4,"min":40,"max":90});
                ob.should.have.property("disk",{"total":85,"count":4,"min":20,"max":25});
                ob.should.have.property("run",{"total":300,"count":4,"min":60,"max":120});
                ob.should.have.property("session",{"total":3,"count":2,"min":1,"max":2});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(4);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Unresolve crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[0]
            };
			request
			.get('/i/crashes/unresolve?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 3000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should be reoccurred', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":6,"unique":3,"resolved":0,"unresolved":3,"fatal":2,"nonfatal":4,"news":0,"renewed":0,"os":{"Android":5, "Windows Phone":1},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 6, crnf: 4, crf: 2, cru: 3, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash details', function(){
		it('should be resolved', function(done){
			request
			.get('/o?group='+CRASHES[0]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[0]);
                ob.should.have.property("os","Android");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                ob.should.have.property("error","java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                ob.should.have.property("nonfatal",true);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("is_renewed",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.3");
                ob.should.have.property("reports",4);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"4:0":3, "4:1":1});
                ob.should.have.property("manufacture",{"Samsung":4});
                ob.should.have.property("device",{"Galaxy S3":3, "Galaxy S4":1});
                ob.should.have.property("resolution",{"480x800":3, "800x1900":1});
                ob.should.have.property("app_version",{"1:1":2, "1:2":1, "1:3":1});
                ob.should.have.property("cpu",{"armv7":4});
                ob.should.have.property("opengl",{"openGL ES 2:0":4});
                ob.should.have.property("orientation",{"landscape":3, "portrait":1});
                ob.should.have.property("custom",{"facebook":{"3:0":3, "3:5":1},"googleplay":{"1:0":3, "2:0":1}});
                ob.should.have.property("root",{"yes":3, "no":1});
                ob.should.have.property("online",{"no":3, "yes":1});
                ob.should.have.property("muted",{"no":3, "yes":1});
                ob.should.have.property("signal",{"yes":3, "no":1});
                ob.should.have.property("background",{"yes":3, "no":1});
                ob.should.have.property("ram",{"total":225,"count":4,"min":50,"max":75});
                ob.should.have.property("bat",{"total":210,"count":4,"min":40,"max":90});
                ob.should.have.property("disk",{"total":85,"count":4,"min":20,"max":25});
                ob.should.have.property("run",{"total":300,"count":4,"min":60,"max":120});
                ob.should.have.property("session",{"total":3,"count":2,"min":1,"max":2});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(4);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Add iOS crash with memory addresses', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "iOS";
            crash._os_version = "8.1";
            crash._device = "iPad3,5";
            crash._resolution = "1576x2048";
            crash._app_version = "1.3";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 2*1024;
			crash._ram_current = 1024;
			crash._disk_total = 10*1024;
			crash._disk_current = 2*1024;
			crash._bat_total = 100;
			crash._bat_current = 40;
			crash._orientation = "landscape";
            
			crash._root = true;
			crash._online = false;
			crash._signal = true;
			crash._muted = false;
			crash._background = true;
            
            crash._name = "-[UIPopoverController dealloc] reached while popover is still visible.";
            
			crash._error = "0 CoreFoundation 0x30629f9b + 154\n"+
            "1 libobjc.A.dylib 0x3b110ccf objc_exception_throw + 38\n"+
            "2 CoreFoundation 0x30629ec5 + 0\n"+
            "3 UIKit 0x33090e75 + 88\n"+
            "4 libobjc.A.dylib 0x3b11fb6b + 174\n"+
            "5 kounter 0x0010427d kounter + 94845\n"+
            "6 UIKit 0x32e7c037 + 90\n"+
            "7 UIKit 0x32e7bfd7 + 30\n"+
            "8 UIKit 0x32e7bfb1 + 44\n"+
            "9 UIKit 0x32e67717 + 374\n"+
            "10 UIKit 0x32e7ba2f + 590\n"+
            "11 UIKit 0x32e7b701 + 528\n"+
            "12 UIKit 0x32e766cb + 758\n"+
            "13 UIKit 0x32e4b8cd + 196\n"+
            "14 UIKit 0x32e49f77 + 7102\n"+
            "15 CoreFoundation 0x305f520b + 14\n"+
            "16 CoreFoundation 0x305f46db + 206\n"+
            "17 CoreFoundation 0x305f2ecf + 622\n"+
            "18 CoreFoundation 0x3055debf CFRunLoopRunSpecific + 522\n"+
            "19 CoreFoundation 0x3055dca3 CFRunLoopRunInMode + 106\n"+
            "20 GraphicsServices 0x35458663 GSEventRunModal + 138\n"+
            "21 UIKit 0x32eaa14d UIApplicationMain + 1136\n"+
            "22 kounter 0x0010735f kounter + 107359\n"+
            "23 libdyld.dylib 0x3b61dab7 + 2";
            crash._run = 60;
            
            crash._custom = {
                "facebook" : "3.0",
                "googleplay" : "1.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'3&app_key='+APP_KEY+"&crash="+encodeURIComponent(JSON.stringify(crash)))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should have new crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":7,"unique":4,"resolved":0,"unresolved":4,"fatal":3,"nonfatal":4,"news":1,"renewed":0,"os":{"Android":5, "Windows Phone":1, "iOS":1},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 7, crnf: 4, crf: 3, cru: 4, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should have new crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 4);
                ob.should.have.property("iTotalDisplayRecords", 4);
                ob.should.have.property("aaData").with.lengthOf(4);
                
                for(var i = 0; i < ob.aaData.length; i++){
                    var crash = ob.aaData[i];
                    if(crash._id != CRASHES[0] && crash._id != CRASHES[1] && crash._id != CRASHES[2]){
                        crash.should.have.property("_id");
                        crash.should.have.property("error", "CoreFoundation 0x30629f9b + 154\nlibobjc.A.dylib 0x3b110ccf objc_exception_throw + 38\nCoreFoundation 0x30629ec5 + 0\nUIKit 0x33090e75 + 88\nlibobjc.A.dylib 0x3b11fb6b + 174\nkounter 0x0010427d kounter + 94845\nUIKit 0x32e7c037 + 90\nUIKit 0x32e7bfd7 + 30\nUIKit 0x32e7bfb1 + 44\nUIKit 0x32e67717 + 374\nUIKit 0x32e7ba2f + 590\nUIKit 0x32e7b701 + 528\nUIKit 0x32e766cb + 758\nUIKit 0x32e4b8cd + 196\nUIKit 0x32e49f77 + 7102\nCoreFoundation 0x305f520b + 14\nCoreFoundation 0x305f46db + 206\nCoreFoundation 0x305f2ecf + 622\nCoreFoundation 0x3055debf CFRunLoopRunSpecific + 522\nCoreFoundation 0x3055dca3 CFRunLoopRunInMode + 106\nGraphicsServices 0x35458663 GSEventRunModal + 138\nUIKit 0x32eaa14d UIApplicationMain + 1136\nkounter 0x0010735f kounter + 107359\nlibdyld.dylib 0x3b61dab7 + 2");
                        crash.should.have.property("is_new", true);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.3");
                        crash.should.have.property("name", "-[UIPopoverController dealloc] reached while popover is still visible.");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'iOS');
                        crash.should.have.property("reports", 1);
                        crash.should.have.property("users", 1);
                        CRASHES[3] = crash._id;
                    }
                }
                setTimeout(done, 1000);
            });
		});
	});
    
    describe('Check crash details', function(){
		it('should have new crash details', function(done){
			request
			.get('/o?group='+CRASHES[3]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[3]);
                ob.should.have.property("os","iOS");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","-[UIPopoverController dealloc] reached while popover is still visible.");
                ob.should.have.property("error","CoreFoundation 0x30629f9b + 154\nlibobjc.A.dylib 0x3b110ccf objc_exception_throw + 38\nCoreFoundation 0x30629ec5 + 0\nUIKit 0x33090e75 + 88\nlibobjc.A.dylib 0x3b11fb6b + 174\nkounter 0x0010427d kounter + 94845\nUIKit 0x32e7c037 + 90\nUIKit 0x32e7bfd7 + 30\nUIKit 0x32e7bfb1 + 44\nUIKit 0x32e67717 + 374\nUIKit 0x32e7ba2f + 590\nUIKit 0x32e7b701 + 528\nUIKit 0x32e766cb + 758\nUIKit 0x32e4b8cd + 196\nUIKit 0x32e49f77 + 7102\nCoreFoundation 0x305f520b + 14\nCoreFoundation 0x305f46db + 206\nCoreFoundation 0x305f2ecf + 622\nCoreFoundation 0x3055debf CFRunLoopRunSpecific + 522\nCoreFoundation 0x3055dca3 CFRunLoopRunInMode + 106\nGraphicsServices 0x35458663 GSEventRunModal + 138\nUIKit 0x32eaa14d UIApplicationMain + 1136\nkounter 0x0010735f kounter + 107359\nlibdyld.dylib 0x3b61dab7 + 2");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",true);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.3");
                ob.should.have.property("reports",1);
                ob.should.have.property("users",1);
                ob.should.have.property("os_version",{"8:1":1});
                ob.should.not.have.property("manufacture");
                ob.should.have.property("device",{"iPad3,5":1});
                ob.should.have.property("resolution",{"1576x2048":1});
                ob.should.have.property("app_version",{"1:3":1});
                ob.should.have.property("cpu",{"ARMv7 A6X":1});
                ob.should.have.property("opengl",{"openGL ES 2:0":1});
                ob.should.have.property("orientation",{"landscape":1});
                ob.should.have.property("custom",{"facebook":{"3:0":1},"googleplay":{"1:0":1}});
                ob.should.have.property("root",{"yes":1});
                ob.should.have.property("online",{"no":1});
                ob.should.have.property("muted",{"no":1});
                ob.should.have.property("signal",{"yes":1});
                ob.should.have.property("background",{"yes":1});
                ob.should.have.property("ram",{"total":50,"count":1,"min":50,"max":50});
                ob.should.have.property("bat",{"total":40,"count":1,"min":40,"max":40});
                ob.should.have.property("disk",{"total":20,"count":1,"min":20,"max":20});
                ob.should.have.property("run",{"total":60,"count":1,"min":60,"max":60});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(1);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Add another iOS crash with different memory addresses', function(){
		it('should success', function(done){
			var crash = {};
            crash._os = "iOS";
            crash._os_version = "8.1";
            crash._device = "iPad3,5";
            crash._resolution = "1576x2048";
            crash._app_version = "1.3";
            crash._opengl = "openGL ES 2.0";
            
            crash._ram_total = 2*1024;
			crash._ram_current = 1024;
			crash._disk_total = 10*1024;
			crash._disk_current = 2*1024;
			crash._bat_total = 100;
			crash._bat_current = 40;
			crash._orientation = "landscape";
            
			crash._root = true;
			crash._online = false;
			crash._signal = true;
			crash._muted = false;
			crash._background = true;
            
            crash._name = "-[UIPopoverController dealloc] reached while popover is still visible.";
            
			crash._error = "0 CoreFoundation 0x2d4b2ee3 + 154\n"+
            "1 libobjc.A.dylib 0x37f93ce7 objc_exception_throw + 38\n"+
            "2 CoreFoundation 0x2d4b2e0d + 0\n"+
            "3 UIKit 0x2ff2e571 + 88\n"+
            "4 libobjc.A.dylib 0x37fa2b6b + 174\n"+
            "5 kounter 0x0009827d kounter + 94845\n"+
            "6 UIKit 0x2fd196a7 + 90\n"+
            "7 UIKit 0x2fd19643 + 38\n"+
            "8 UIKit 0x2fd19613 + 46\n"+
            "9 UIKit 0x2fd04d5b + 374\n"+
            "10 UIKit 0x2fd1905b + 594\n"+
            "11 UIKit 0x2fd18d2d + 528\n"+
            "12 UIKit 0x2fd13c87 + 758\n"+
            "13 UIKit 0x2fce8e55 + 196\n"+
            "14 UIKit 0x2fce7521 + 7120\n"+
            "15 CoreFoundation 0x2d47dfaf + 14\n"+
            "16 CoreFoundation 0x2d47d477 + 206\n"+
            "17 CoreFoundation 0x2d47bc67 + 630\n"+
            "18 CoreFoundation 0x2d3e6729 CFRunLoopRunSpecific + 524\n"+
            "19 CoreFoundation 0x2d3e650b CFRunLoopRunInMode + 106\n"+
            "20 GraphicsServices 0x323226d3 GSEventRunModal + 138\n"+
            "21 UIKit 0x2fd47871 UIApplicationMain + 1136\n"+
            "22 kounter 0x0009b35f kounter + 107359\n"+
            "23 libdyld.dylib 0x38491ab7 + 2";
            crash._run = 60;
            
            crash._custom = {
                "facebook" : "3.0",
                "googleplay" : "1.0"
            };
			request
			.get('/i?device_id='+DEVICE_ID+'2&app_key='+APP_KEY+"&crash="+encodeURIComponent(JSON.stringify(crash)))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should be the same crash as previous', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":8,"unique":4,"resolved":0,"unresolved":4,"fatal":4,"nonfatal":4,"news":0,"renewed":0,"os":{"Android":5, "Windows Phone":1, "iOS":2},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 8, crnf: 4, crf: 4, cru: 4, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should be the same crash as previous', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 4);
                ob.should.have.property("iTotalDisplayRecords", 4);
                ob.should.have.property("aaData").with.lengthOf(4);
                
                for(var i = 0; i < ob.aaData.length; i++){
                    var crash = ob.aaData[i];
                    if(crash._id == CRASHES[3]){
                        crash.should.have.property("_id", CRASHES[3]);
                        crash.should.have.property("error", "CoreFoundation 0x2d4b2ee3 + 154\nlibobjc.A.dylib 0x37f93ce7 objc_exception_throw + 38\nCoreFoundation 0x2d4b2e0d + 0\nUIKit 0x2ff2e571 + 88\nlibobjc.A.dylib 0x37fa2b6b + 174\nkounter 0x0009827d kounter + 94845\nUIKit 0x2fd196a7 + 90\nUIKit 0x2fd19643 + 38\nUIKit 0x2fd19613 + 46\nUIKit 0x2fd04d5b + 374\nUIKit 0x2fd1905b + 594\nUIKit 0x2fd18d2d + 528\nUIKit 0x2fd13c87 + 758\nUIKit 0x2fce8e55 + 196\nUIKit 0x2fce7521 + 7120\nCoreFoundation 0x2d47dfaf + 14\nCoreFoundation 0x2d47d477 + 206\nCoreFoundation 0x2d47bc67 + 630\nCoreFoundation 0x2d3e6729 CFRunLoopRunSpecific + 524\nCoreFoundation 0x2d3e650b CFRunLoopRunInMode + 106\nGraphicsServices 0x323226d3 GSEventRunModal + 138\nUIKit 0x2fd47871 UIApplicationMain + 1136\nkounter 0x0009b35f kounter + 107359\nlibdyld.dylib 0x38491ab7 + 2");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.3");
                        crash.should.have.property("name", "-[UIPopoverController dealloc] reached while popover is still visible.");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'iOS');
                        crash.should.have.property("reports", 2);
                        crash.should.have.property("users", 2);
                    }
                }
                setTimeout(done, 1000);
            });
		});
	});
    
    describe('Check crash details', function(){
		it('should be the same crash as previous', function(done){
			request
			.get('/o?group='+CRASHES[3]+'&method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("_id",CRASHES[3]);
                ob.should.have.property("os","iOS");
                ob.should.have.property("lastTs");
                ob.should.have.property("name","-[UIPopoverController dealloc] reached while popover is still visible.");
                ob.should.have.property("error","CoreFoundation 0x2d4b2ee3 + 154\nlibobjc.A.dylib 0x37f93ce7 objc_exception_throw + 38\nCoreFoundation 0x2d4b2e0d + 0\nUIKit 0x2ff2e571 + 88\nlibobjc.A.dylib 0x37fa2b6b + 174\nkounter 0x0009827d kounter + 94845\nUIKit 0x2fd196a7 + 90\nUIKit 0x2fd19643 + 38\nUIKit 0x2fd19613 + 46\nUIKit 0x2fd04d5b + 374\nUIKit 0x2fd1905b + 594\nUIKit 0x2fd18d2d + 528\nUIKit 0x2fd13c87 + 758\nUIKit 0x2fce8e55 + 196\nUIKit 0x2fce7521 + 7120\nCoreFoundation 0x2d47dfaf + 14\nCoreFoundation 0x2d47d477 + 206\nCoreFoundation 0x2d47bc67 + 630\nCoreFoundation 0x2d3e6729 CFRunLoopRunSpecific + 524\nCoreFoundation 0x2d3e650b CFRunLoopRunInMode + 106\nGraphicsServices 0x323226d3 GSEventRunModal + 138\nUIKit 0x2fd47871 UIApplicationMain + 1136\nkounter 0x0009b35f kounter + 107359\nlibdyld.dylib 0x38491ab7 + 2");
                ob.should.have.property("nonfatal",false);
                ob.should.have.property("is_new",false);
                ob.should.have.property("is_resolved",false);
                ob.should.have.property("startTs");
                ob.should.have.property("latest_version","1.3");
                ob.should.have.property("reports",2);
                ob.should.have.property("users",2);
                ob.should.have.property("os_version",{"8:1":2});
                ob.should.not.have.property("manufacture");
                ob.should.have.property("device",{"iPad3,5":2});
                ob.should.have.property("resolution",{"1576x2048":2});
                ob.should.have.property("app_version",{"1:3":2});
                ob.should.have.property("cpu",{"ARMv7 A6X":2});
                ob.should.have.property("opengl",{"openGL ES 2:0":2});
                ob.should.have.property("orientation",{"landscape":2});
                ob.should.have.property("custom",{"facebook":{"3:0":2},"googleplay":{"1:0":2}});
                ob.should.have.property("root",{"yes":2});
                ob.should.have.property("online",{"no":2});
                ob.should.have.property("muted",{"no":2});
                ob.should.have.property("signal",{"yes":2});
                ob.should.have.property("background",{"yes":2});
                ob.should.have.property("ram",{"total":100,"count":2,"min":50,"max":50});
                ob.should.have.property("bat",{"total":80,"count":2,"min":40,"max":40});
                ob.should.have.property("disk",{"total":40,"count":2,"min":20,"max":20});
                ob.should.have.property("run",{"total":120,"count":2,"min":60,"max":60});
                ob.should.have.property("total",3);
                ob.should.have.property("url");
                ob.should.have.property("data").with.lengthOf(2);
                
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Delete first crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[1]
            };
			request
			.get('/i/crashes/delete?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should not have first crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":7,"unique":3,"resolved":0,"unresolved":3,"fatal":3,"nonfatal":4,"news":0,"renewed":0,"os":{"Android":4, "Windows Phone":1, "iOS":2},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 8, crnf: 4, crf: 4, cru: 4, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should not have first crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 3);
                ob.should.have.property("iTotalDisplayRecords", 3);
                ob.should.have.property("aaData").with.lengthOf(3);
                
                for(var i = 0; i < ob.aaData.length; i++){
                    var crash = ob.aaData[i];
                    if(crash._id == CRASHES[2]){
                        crash.should.have.property("_id", CRASHES[2]);
                        crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.2");
                        crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'Windows Phone');
                        crash.should.have.property("reports", 1);
                        crash.should.have.property("users", 1);
                    }
                    else if(crash._id == CRASHES[0]){
                        crash.should.have.property("_id", CRASHES[0]);
                        crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.3");
                        crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                        crash.should.have.property("nonfatal", true);
                        crash.should.have.property("os", 'Android');
                        crash.should.have.property("reports", 4);
                        crash.should.have.property("users", 1);
                    }
                    else{
                        crash.should.have.property("_id", CRASHES[3]);
                        crash.should.have.property("error", "CoreFoundation 0x2d4b2ee3 + 154\nlibobjc.A.dylib 0x37f93ce7 objc_exception_throw + 38\nCoreFoundation 0x2d4b2e0d + 0\nUIKit 0x2ff2e571 + 88\nlibobjc.A.dylib 0x37fa2b6b + 174\nkounter 0x0009827d kounter + 94845\nUIKit 0x2fd196a7 + 90\nUIKit 0x2fd19643 + 38\nUIKit 0x2fd19613 + 46\nUIKit 0x2fd04d5b + 374\nUIKit 0x2fd1905b + 594\nUIKit 0x2fd18d2d + 528\nUIKit 0x2fd13c87 + 758\nUIKit 0x2fce8e55 + 196\nUIKit 0x2fce7521 + 7120\nCoreFoundation 0x2d47dfaf + 14\nCoreFoundation 0x2d47d477 + 206\nCoreFoundation 0x2d47bc67 + 630\nCoreFoundation 0x2d3e6729 CFRunLoopRunSpecific + 524\nCoreFoundation 0x2d3e650b CFRunLoopRunInMode + 106\nGraphicsServices 0x323226d3 GSEventRunModal + 138\nUIKit 0x2fd47871 UIApplicationMain + 1136\nkounter 0x0009b35f kounter + 107359\nlibdyld.dylib 0x38491ab7 + 2");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.3");
                        crash.should.have.property("name", "-[UIPopoverController dealloc] reached while popover is still visible.");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'iOS');
                        crash.should.have.property("reports", 2);
                        crash.should.have.property("users", 2);
                    }
                }
                setTimeout(done, 1000);
            });
		});
	});
    
    describe('Delete second crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[2]
            };
			request
			.get('/i/crashes/delete?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should not have second crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":3,"fatal":2,"nonfatal":1});
                ob.should.have.property("crashes", {"total":6,"unique":2,"resolved":0,"unresolved":2,"fatal":2,"nonfatal":4,"news":0,"renewed":0,"os":{"Android":4, "Windows Phone":0, "iOS":2},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 8, crnf: 4, crf: 4, cru: 4, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should not have second crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 2);
                ob.should.have.property("iTotalDisplayRecords", 2);
                ob.should.have.property("aaData").with.lengthOf(2);
                
                for(var i = 0; i < ob.aaData.length; i++){
                    var crash = ob.aaData[i];
                    if(crash._id == CRASHES[0]){
                        crash.should.have.property("_id", CRASHES[0]);
                        crash.should.have.property("error", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;\nat com.domain.app.&lt;init&gt;(Activity.java:32)\nat com.domain.app.&lt;init&gt;(Activity.java:24)\nat com.domain.app.&lt;init&gt;(Activity.java:12)");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.3");
                        crash.should.have.property("name", "java.lang.NullPointerException: com.domain.app.Exception&lt;init&gt;");
                        crash.should.have.property("nonfatal", true);
                        crash.should.have.property("os", 'Android');
                        crash.should.have.property("reports", 4);
                        crash.should.have.property("users", 1);
                    }
                    else if(crash._id == CRASHES[3]){
                        crash.should.have.property("_id", CRASHES[3]);
                        crash.should.have.property("error", "CoreFoundation 0x2d4b2ee3 + 154\nlibobjc.A.dylib 0x37f93ce7 objc_exception_throw + 38\nCoreFoundation 0x2d4b2e0d + 0\nUIKit 0x2ff2e571 + 88\nlibobjc.A.dylib 0x37fa2b6b + 174\nkounter 0x0009827d kounter + 94845\nUIKit 0x2fd196a7 + 90\nUIKit 0x2fd19643 + 38\nUIKit 0x2fd19613 + 46\nUIKit 0x2fd04d5b + 374\nUIKit 0x2fd1905b + 594\nUIKit 0x2fd18d2d + 528\nUIKit 0x2fd13c87 + 758\nUIKit 0x2fce8e55 + 196\nUIKit 0x2fce7521 + 7120\nCoreFoundation 0x2d47dfaf + 14\nCoreFoundation 0x2d47d477 + 206\nCoreFoundation 0x2d47bc67 + 630\nCoreFoundation 0x2d3e6729 CFRunLoopRunSpecific + 524\nCoreFoundation 0x2d3e650b CFRunLoopRunInMode + 106\nGraphicsServices 0x323226d3 GSEventRunModal + 138\nUIKit 0x2fd47871 UIApplicationMain + 1136\nkounter 0x0009b35f kounter + 107359\nlibdyld.dylib 0x38491ab7 + 2");
                        crash.should.have.property("is_new", false);
                        crash.should.have.property("is_resolved", false);
                        crash.should.have.property("lastTs");
                        crash.should.have.property("latest_version", "1.3");
                        crash.should.have.property("name", "-[UIPopoverController dealloc] reached while popover is still visible.");
                        crash.should.have.property("nonfatal", false);
                        crash.should.have.property("os", 'iOS');
                        crash.should.have.property("reports", 2);
                        crash.should.have.property("users", 2);
                    }
                }
                setTimeout(done, 1000);
            });
		});
	});
    
    describe('Delete third crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[0]
            };
			request
			.get('/i/crashes/delete?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should not have third crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":1,"fatal":1,"nonfatal":0});
                ob.should.have.property("crashes", {"total":2,"unique":1,"resolved":0,"unresolved":1,"fatal":2,"nonfatal":0,"news":0,"renewed":0,"os":{"Android":0, "Windows Phone":0, "iOS":2},"highest_app":"1.3"});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 8, crnf: 4, crf: 4, cru: 4, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should not have third crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 1);
                ob.should.have.property("iTotalDisplayRecords", 1);
                ob.should.have.property("aaData").with.lengthOf(1);
                
                var crash3 = ob.aaData[0];
                crash3.should.have.property("_id", CRASHES[3]);
                crash3.should.have.property("error", "CoreFoundation 0x2d4b2ee3 + 154\nlibobjc.A.dylib 0x37f93ce7 objc_exception_throw + 38\nCoreFoundation 0x2d4b2e0d + 0\nUIKit 0x2ff2e571 + 88\nlibobjc.A.dylib 0x37fa2b6b + 174\nkounter 0x0009827d kounter + 94845\nUIKit 0x2fd196a7 + 90\nUIKit 0x2fd19643 + 38\nUIKit 0x2fd19613 + 46\nUIKit 0x2fd04d5b + 374\nUIKit 0x2fd1905b + 594\nUIKit 0x2fd18d2d + 528\nUIKit 0x2fd13c87 + 758\nUIKit 0x2fce8e55 + 196\nUIKit 0x2fce7521 + 7120\nCoreFoundation 0x2d47dfaf + 14\nCoreFoundation 0x2d47d477 + 206\nCoreFoundation 0x2d47bc67 + 630\nCoreFoundation 0x2d3e6729 CFRunLoopRunSpecific + 524\nCoreFoundation 0x2d3e650b CFRunLoopRunInMode + 106\nGraphicsServices 0x323226d3 GSEventRunModal + 138\nUIKit 0x2fd47871 UIApplicationMain + 1136\nkounter 0x0009b35f kounter + 107359\nlibdyld.dylib 0x38491ab7 + 2");
                crash3.should.have.property("is_new", false);
                crash3.should.have.property("is_resolved", false);
                crash3.should.have.property("lastTs");
                crash3.should.have.property("latest_version", "1.3");
                crash3.should.have.property("name", "-[UIPopoverController dealloc] reached while popover is still visible.");
                crash3.should.have.property("nonfatal", false);
                crash3.should.have.property("os", 'iOS');
                crash3.should.have.property("reports", 2);
                crash3.should.have.property("users", 2);
                setTimeout(done, 1000); 
            });
		});
	});
    
    describe('Delete fourth crash', function(){
		it('should success', function(done){
            var args = {
                crash_id: CRASHES[3]
            };
			request
			.get('/i/crashes/delete?args='+JSON.stringify(args)+'&app_id='+APP_ID+'&api_key='+API_KEY_ADMIN)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result','Success');
				setTimeout(done, 10000);
			});
		});
	});
    
    describe('Check crash metrics', function(){
		it('should not have fourth crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":3,"affected":0,"fatal":0,"nonfatal":0});
                ob.should.have.property("crashes", {"total":0,"unique":0,"resolved":0,"unresolved":0,"fatal":0,"nonfatal":0,"news":0,"renewed":0,"os":{"Android":0, "Windows Phone":0, "iOS":0},"highest_app":""});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data");
                verifyMetrics(ob.data, {meta:{}, cr: 8, crnf: 4, crf: 4, cru: 4, crru:2});
				setTimeout(done, 1000);
			});
		});
	});
    
    describe('Check crash data', function(){
		it('should not have fourth crash', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 0);
                ob.should.have.property("iTotalDisplayRecords", 0);
                ob.should.have.property("aaData").with.lengthOf(0);
                setTimeout(done, 1000);
            });
		});
	});
    
	describe('Reset app', function(){
		it('should reset data', function(done){
			var params = {app_id:APP_ID};
			request
			.get('/i/apps/reset?api_key='+API_KEY_ADMIN+"&args="+JSON.stringify(params))
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
				ob.should.have.property('result', 'Success');
				setTimeout(done, 5000)
			});
		});
	});
    
    describe('Verify reset metrics', function(){
		it('should be empty', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID+"&graph=1")
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("users", {"total":0,"affected":0,"fatal":0,"nonfatal":0});
                ob.should.have.property("crashes", {"total":0,"unique":0,"resolved":0,"unresolved":0,"fatal":0,"nonfatal":0,"news":0,"renewed":0,"os":{},"highest_app":""});
                ob.should.have.property("loss", 0);
                ob.should.have.property("data", {});
				setTimeout(done, 100)
			});
		});
	});
    
    describe('Verify reset data', function(){
		it('should be empty', function(done){
			request
			.get('/o?method=crashes&api_key='+API_KEY_ADMIN+"&app_id="+APP_ID)
			.expect(200)
			.end(function(err, res){
				if (err) return done(err);
				var ob = JSON.parse(res.text);
                ob.should.have.property("iTotalRecords", 0);
                ob.should.have.property("iTotalDisplayRecords", 0);
                ob.should.have.property("aaData").with.lengthOf(0);
                setTimeout(done, 1000);
            });
		});
	});
});